/**
 * Copyright (c) 2018, 西安星沙网络科技-版权所有
 *
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.waleychain.exchange.service.impl.account;

import java.math.BigDecimal;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.Page;

import cn.waleychain.exchange.core.SysParaKey;
import cn.waleychain.exchange.core.constant.DDIC;
import cn.waleychain.exchange.core.constant.DDIC.AccountChangeStatus;
import cn.waleychain.exchange.core.constant.OperatePaymentRemark;
import cn.waleychain.exchange.core.constant.OperatePaymentType;
import cn.waleychain.exchange.core.constant.SmsContent;
import cn.waleychain.exchange.core.entity.PageInfo;
import cn.waleychain.exchange.core.exec.CoinWalletBalanceNotEnoughException;
import cn.waleychain.exchange.core.exec.CoinWalletFreezeNotEnoughException;
import cn.waleychain.exchange.core.exec.CoinWalletOperationException;
import cn.waleychain.exchange.core.result.RetResultCode;
import cn.waleychain.exchange.core.utils.BigDecimalUtils;
import cn.waleychain.exchange.core.utils.PageHelper;
import cn.waleychain.exchange.core.utils.RandomUtils;
import cn.waleychain.exchange.core.utils.SequenceUtils;
import cn.waleychain.exchange.core.vaildate.VaildateHelper;
import cn.waleychain.exchange.dao.AccountChangeMapper;
import cn.waleychain.exchange.dao.AccountRechargeMapper;
import cn.waleychain.exchange.dao.AccountWithdrawMapper;
import cn.waleychain.exchange.dao.UserAccountMapper;
import cn.waleychain.exchange.dao.UserBankMapper;
import cn.waleychain.exchange.dao.UserInfoMapper;
import cn.waleychain.exchange.feign.CoinServiceFeign;
import cn.waleychain.exchange.feign.CoinWalletServiceFeign;
import cn.waleychain.exchange.feign.CommonServiceFeign;
import cn.waleychain.exchange.feign.ConfigServiceFeign;
import cn.waleychain.exchange.model.AccountChange;
import cn.waleychain.exchange.model.AccountRecharge;
import cn.waleychain.exchange.model.AccountWithdraw;
import cn.waleychain.exchange.model.CoinWallet;
import cn.waleychain.exchange.model.UserAccount;
import cn.waleychain.exchange.service.account.AccountService;
import cn.waleychain.exchange.service.account.UserService;
import cn.waleychain.exchange.service.impl.BaseServiceImpl;

@Service
public class AccountServiceImpl extends BaseServiceImpl implements AccountService {

	@Autowired
	private UserAccountMapper userAccountMapper;
	
	@Autowired
	private AccountWithdrawMapper accountWithdrawMapper;
	
	@Autowired
	private AccountRechargeMapper accountRechargeMapper;
	
	@Autowired
	private AccountChangeMapper accountChangeMapper;
	
	@Autowired
	private UserInfoMapper userMapper;
	
	@Autowired
	private ConfigServiceFeign configFeign;
	
	@Autowired
	private CommonServiceFeign commonFeign;
	
	@Autowired
	private UserBankMapper userBankMapper;
	
	@Autowired
	private CoinServiceFeign coinFeign;
	
	@Autowired
	private CoinWalletServiceFeign coinWalletFeign;
	
	@Autowired
	private UserService userService;
	
	@Override
	public PageInfo<UserAccount> fetchAccountPageList(String userName, String realName, String mobile, Integer status, BigDecimal begin, BigDecimal end, int showCount, int currentPage) throws Exception {

		PageHelper.startPage(currentPage, showCount);
		Page<UserAccount> page = userAccountMapper.fetchAccountPageList(userName, realName, mobile, status, begin, end);
		
		return new PageInfo<>(page);
	}

	@Override
	public UserAccount fetchAccountInfo(Long accountId) throws Exception {

		return userAccountMapper.queryByPrimaryKey(accountId);
	}

	@Override
	public PageInfo<AccountWithdraw> fetchAccountWithdrowPageList(String userName, String realName, Date beginDate, Date endDate, Integer status, int showCount, int currentPage) throws Exception {

		PageHelper.startPage(currentPage, showCount);
		Page<AccountWithdraw> page = accountWithdrawMapper.fetchAccountWithdrawPageList(userName, realName, beginDate, endDate, status);
		
		return new PageInfo<>(page);
	}

	@Override
	public PageInfo<AccountRecharge> fetchAccountRechargePageList(String userName, String realName, Date beginDate, Date endDate, Integer status, String tradeNo, int showCount, int currentPage) throws Exception {

		PageHelper.startPage(currentPage, showCount);
		Page<AccountRecharge> page = accountRechargeMapper.fetchAccountRechargePageList(userName, realName, beginDate, endDate, status, tradeNo);
		
		return new PageInfo<>(page);
	}

	@Override
	@Transactional
	public boolean setAccountWithdrawStatus(Long idNo, Integer status, String remark) throws Exception {
		
		AccountWithdraw accountWithdraw = accountWithdrawMapper.fetchAccountWithdrawById(idNo);
		VaildateHelper.vaildateBooleanResult(accountWithdraw == null, RetResultCode.E20022);
		
		// 获取用户资金账号
		UserAccount account = userAccountMapper.queryByPrimaryKey(accountWithdraw.getAccountId());
		VaildateHelper.vaildateBooleanResult(account == null, RetResultCode.E20020);
		
		AccountChange change = new AccountChange();
		change.setIdNo(accountWithdraw.getChangeId());
		change.setStatus(status);
		change.setRemark(remark);
		long btcxCoinId = coinFeign.fetchBtcxCoinId();
		// 根据审核状态操作业务
		AccountChangeStatus stat = DDIC.AccountChangeStatus.convertId(status);
		switch (stat) {
		case STATUS_30:
			// 不做操作
			break;
		case STATUS_31:
			// 拒绝，将资金返回用户
			this.unfreezeAmount(account.getAccountId(), accountWithdraw.getAmount(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAW_CNY, accountWithdraw.getIdNo());
			this.coinWalletFeign.walletUnfreezeAmount(account.getUserId(), btcxCoinId, accountWithdraw.getAmount(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_CNY_BTCX_EXCHANGE, accountWithdraw.getIdNo());
			break;
		case STATUS_32:
			// 审核通过
			// 先解冻资金
			this.unfreezeAmount(account.getAccountId(), accountWithdraw.getAmount(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAW_CNY, accountWithdraw.getIdNo());
			
			// 获取系统的资金账号
			long adminUserId = userService.fetchAdminUserId();
			UserAccount adminAccount = userAccountMapper.fetchAccountByUserId(adminUserId);
			VaildateHelper.vaildateBooleanResult(adminAccount == null, RetResultCode.E20020, userService);
			
			this.transferAmount(account.getAccountId(), adminAccount.getAccountId(), accountWithdraw.getFee(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAW_CNY_POUNDAGE, accountWithdraw.getIdNo());
			this.withdrawalsAmount(account.getAccountId(), accountWithdraw.getAmountReal(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAW_CNY);
			
			// 钱包提现
			CoinWallet userCoinWallet = this.coinWalletFeign.fetchCoinWalletInfo(account.getUserId(), btcxCoinId);
			vaildateCoinWallet(userCoinWallet, true);
			CoinWallet adminCoinWallet = this.coinWalletFeign.fetchCoinWalletInfo(adminUserId, btcxCoinId);
			vaildateCoinWallet(adminCoinWallet, true);
			this.coinWalletFeign.walletUnfreezeAmount(account.getUserId(), btcxCoinId, accountWithdraw.getAmount(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_CNY_BTCX_EXCHANGE, accountWithdraw.getIdNo());
			this.coinWalletFeign.transferAmount(userCoinWallet.getCoinWalletId(), adminCoinWallet.getCoinWalletId(), btcxCoinId, accountWithdraw.getFee(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAWALS_POUNDAGE, accountWithdraw.getIdNo());
			this.coinWalletFeign.withdrawalsAmount(userCoinWallet.getCoinWalletId(), btcxCoinId, accountWithdraw.getAmountReal(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAWALS);
			
			break;

		default:
			VaildateHelper.vaildateBooleanResult(true, RetResultCode.E11001, "设置提现状态错误：" + status);
			break;
		}
		
		return accountChangeMapper.updateByPrimaryKeySelective(change) > 0;
	}
	
	@Override
	@Transactional
	public boolean setAccountRechargeStatus(Long idNo, Integer status, String remark) throws Exception {

		// 获取提现记录
		AccountRecharge accountRecharge = accountRechargeMapper.fetchAccountRechargeById(idNo);
		VaildateHelper.vaildateBooleanResult(accountRecharge == null, RetResultCode.E20021);
		
		// 获取用户信息，发送短信
		// 获取用户资金账号
		UserAccount account = userAccountMapper.fetchAccountById(accountRecharge.getAccountId());
		VaildateHelper.vaildateBooleanResult(account == null, RetResultCode.E20020);
		
		AccountChange change = new AccountChange();
		change.setIdNo(accountRecharge.getChangeId());
		change.setStatus(status);
		change.setRemark(remark);
		
		// 短信内容
		String smsContent = "";
		
		// 根据审核状态操作业务
		AccountChangeStatus stat = DDIC.AccountChangeStatus.convertId(status);
		switch (stat) {
		case NOTPAY:
			// 审核拒绝
			smsContent = SmsContent.genAccountRechargeReviewRefuse(accountRecharge.getAmountReal(), remark);
			break;
		case TO_SUCCESS:
			// 到账成功
			break;
		case LABOUR:
			// 人工到账
			
			AccountRecharge updateRecharge = new AccountRecharge();
			updateRecharge.setIdNo(accountRecharge.getIdNo());
			updateRecharge.setModifiedTime(new Date());
			updateRecharge.setAmountReal(accountRecharge.getAmount());
			
			accountRechargeMapper.updateByPrimaryKeySelective(updateRecharge);
			
			UserAccount updateAccount2 = new UserAccount();
			updateAccount2.setAccountId(account.getAccountId());
			updateAccount2.setBalance(account.getBalance().add(accountRecharge.getAmountReal()));
			updateAccount2.setModifiedTime(new Date());
			
			userAccountMapper.updateByPrimaryKeySelective(updateAccount2);
			
			smsContent = SmsContent.genAccountRechargeLabour(accountRecharge.getAmountReal(), updateAccount2.getModifiedTime());
			
			// 给用户充值btcx币
			long btcxCoinId = coinFeign.fetchBtcxCoinId();
			this.coinWalletFeign.rechargeAmount(account.getUserId(), btcxCoinId, accountRecharge.getAmount(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_CNY_BTCX_EXCHANGE.getRemark());
			
			this.createPaymentDetail(account.getUserId(), null, account.getAccountId(), account.getAccountId(), accountRecharge.getIdNo(),  
					DDIC.TradeDetailType.TRADE_DETAIL_TYPE_INCOME.id, OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_RECHARGE.getRemark(), accountRecharge.getAmount(), OperatePaymentRemark.RECHARGE.getRemark());
			
			break;
		case BEING_PROCESSED:
			// 处理中
			break;
		default:
			VaildateHelper.vaildateBooleanResult(true, RetResultCode.E11001, "设置充值状态错误：" + status);
			break;
		}
		
		if (accountChangeMapper.updateByPrimaryKeySelective(change) > 0) {
			// 发送短信
			commonFeign.sendSms(account.getMobile(), smsContent);
			
			return true;
		}
		
		return false;
	}

	@Override
	@Transactional
	public boolean addAccountWithdraw(AccountWithdraw accountWithdraw, Long userId, 
			String payPassword) throws Exception {

		// 判断支付密码是否正确
		boolean isCorrect = userMapper.checkPayPassword(userId, payPassword) > 0;
		VaildateHelper.vaildateBooleanResult(!isCorrect, RetResultCode.E11001, "支付密码错误");
		
		// 验证银行卡
		boolean isExist = userBankMapper.checkBankIsUser(userId, accountWithdraw.getUserBankId()) > 0;
		VaildateHelper.vaildateBooleanResult(!isExist, RetResultCode.E11001, "不存在此银行卡，或已被停用");
		
		// 提现资金是否充足
		UserAccount account = userAccountMapper.fetchAccountByUserId(userId);
		VaildateHelper.vaildateBooleanResult(account == null, RetResultCode.E20020);
		
		// 判断账号是否可用
		VaildateHelper.vaildateBooleanResult(DDIC.UserAccountStatus.ENABLED.id != account.getStatus(), RetResultCode.E20013);
		
		VaildateHelper.vaildateBooleanResult(accountWithdraw.getAmount().compareTo(account.getBalance()) == 1, 
				RetResultCode.E20012); // 可用余额小于提现金额，可用余额不足
		
		// 最小提现额
		BigDecimal mixAmount = new BigDecimal(configFeign.fetchSystemConfigValue(SysParaKey.TRADE_CONFIG_WITHDRAWALS_MIN_AMOUNT));
		
		// 单笔最大提现额
		BigDecimal simpleMaxAmount = new BigDecimal(configFeign.fetchSystemConfigValue(SysParaKey.TRADE_CONFIG_WITHDRAWALS_MAX_AMOUNT));
		
		// 单日最大提现额
		BigDecimal dayMaxAmount = new BigDecimal(configFeign.fetchSystemConfigValue(SysParaKey.TRADE_CONFIG_WITHDRAWALS_MAX_AMOUNT_PERDAY));
		
		// 提现费率
		BigDecimal rate = new BigDecimal(configFeign.fetchSystemConfigValue(SysParaKey.TRADE_CONFIG_WITHDRAWALS_POUNDAGE_RATE));
		// 最小提现手续费
		BigDecimal mixPoundage = new BigDecimal(configFeign.fetchSystemConfigValue(SysParaKey.TRADE_CONFIG_WITHDRAWALS_MIN_POUNDAGE));
		// 提现基数
		BigDecimal baseAmount = new BigDecimal(configFeign.fetchSystemConfigValue(SysParaKey.TRADE_CONFIG_WITHDRAWALS_BASEAMOUNT));

		// 先判断提现基数
		VaildateHelper.vaildateBooleanResult(accountWithdraw.getAmount().remainder(baseAmount).compareTo(BigDecimal.ZERO) != 0, 
				RetResultCode.E11001, "提现金额有误，必须是：" + baseAmount.doubleValue() + " 的倍数");
		
		// 判断最小提现额
		VaildateHelper.vaildateBooleanResult(mixAmount.compareTo(accountWithdraw.getAmount()) == 1, RetResultCode.E11001, "最小体现额：" + mixAmount.doubleValue());
		
		// 判断最大提现额
		VaildateHelper.vaildateBooleanResult(accountWithdraw.getAmount().compareTo(simpleMaxAmount) == 1, RetResultCode.E11001, "单笔提现限额：" + simpleMaxAmount.doubleValue());
		
		// 判断单日最大提现额
		BigDecimal userDayWithdrawAmount = accountWithdrawMapper.fetchSimpleDaySumWithdrawAmount(accountWithdraw.getAccountId());
		userDayWithdrawAmount = userDayWithdrawAmount.add(accountWithdraw.getAmount());
		VaildateHelper.vaildateBooleanResult(userDayWithdrawAmount.compareTo(dayMaxAmount) == 1, RetResultCode.E11001, "超过单日最大提现限额：" + dayMaxAmount.doubleValue());
		
		// 计算手续费
		BigDecimal fee = accountWithdraw.getAmount().multiply(rate);
		if (fee.compareTo(mixPoundage) == -1) {
			fee = mixPoundage;
		}
		accountWithdraw.setAmountReal(accountWithdraw.getAmount().subtract(fee));
		accountWithdraw.setFee(fee);

		accountWithdraw.setAccountId(account.getAccountId());
		
		AccountChange change = new AccountChange();
		change.setAccountId(accountWithdraw.getAccountId());
		change.setBizType(DDIC.AccountBizType.ACCOUNT_WITHDRAW_3.id);
		change.setBizTypeId(accountWithdraw.getIdNo());
		change.setType(DDIC.AccountChangeType.PAYOUT_2.id);
		change.setStatus(DDIC.AccountChangeStatus.STATUS_30.id);
		change.setCreateTime(new Date());
		
		// 冻结用户资金
		boolean bool3 = this.freezeAmount(account.getAccountId(), accountWithdraw.getAmount(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_WITHDRAW_CNY, accountWithdraw.getIdNo());
		
		boolean bool1 = accountWithdrawMapper.insertSelective(accountWithdraw) > 0;
		boolean bool2 = accountChangeMapper.insertSelective(change) > 0;
		
		boolean result = bool1 && bool2 && bool3;
		if (result) {
			// 冻结btcx钱包账号
			long btcxCoinId = coinFeign.fetchBtcxCoinId();
			this.coinWalletFeign.walletFreezeAmount(userId, btcxCoinId, accountWithdraw.getAmount(), OperatePaymentType.TRADE_DETAIL_REMARK_TYPE_CNY_BTCX_EXCHANGE, accountWithdraw.getIdNo());
		}
		
		return result;
	}

	@Override
	public AccountRecharge addAccountRecharge(Long userId, BigDecimal amount, Integer payType) throws Exception {

		// 获取用户
		UserAccount userAccount = userAccountMapper.fetchAccountByUserId(userId);
		VaildateHelper.vaildateBooleanResult(userAccount == null, RetResultCode.E20020, userId);
		
		VaildateHelper.vaildateBooleanResult(0 > amount.doubleValue() , RetResultCode.E11001, "金额有误");
		
		AccountRecharge accountRecharge = new AccountRecharge();
		accountRecharge.setIdNo(SequenceUtils.generateDefaultSerialNum());
		accountRecharge.setAccountId(userAccount.getAccountId());
		accountRecharge.setAmount(amount);
		accountRecharge.setFee(BigDecimalUtils.genInitValue());
		accountRecharge.setAmountReal(amount);
		accountRecharge.setType(payType);
		accountRecharge.setTradeNo(RandomUtils.genRandomUpperAlphaAndDec(5));
		accountRecharge.setCreateTime(new Date());
		accountRecharge.setModifiedTime(new Date());
		
		AccountChange change = new AccountChange();
		change.setAccountId(accountRecharge.getAccountId());
		change.setBizType(DDIC.AccountBizType.ACCOUNT_RECHARGE_4.id);
		change.setBizTypeId(accountRecharge.getIdNo());
		change.setType(DDIC.AccountChangeType.INCOME_1.id);
		change.setStatus(DDIC.AccountChangeStatus.NOTPAY.id);
		change.setCreateTime(new Date());
		
		boolean bool1 = accountRechargeMapper.insertSelective(accountRecharge) > 0;
		boolean bool2 = accountChangeMapper.insertSelective(change) > 0;
		
		if (bool1 && bool2) {
			accountRecharge.setStatus(change.getStatus());
			return accountRecharge;
		}
		
		return null;
	}
	

	@Override
	public boolean freezeAmount(Long accountId, BigDecimal freezeAmount, OperatePaymentType paymentType, Long orderId) throws Exception {

		// 获取账户
		UserAccount account = userAccountMapper.fetchAccountById(accountId);
		this.vaildateUserAccount(account, true);
		
		if (account.getBalance().max(freezeAmount) == freezeAmount) {
			throw new CoinWalletBalanceNotEnoughException(RetResultCode.E30007);
		} else {
			// 冻结金额
			// 冻结用户资金
			UserAccount updateAccount = new UserAccount();
			updateAccount.setAccountId(account.getAccountId());
			updateAccount.setBalance(account.getBalance().subtract(freezeAmount));
			updateAccount.setFreeze(account.getFreeze().add(freezeAmount));
			updateAccount.setModifiedTime(new Date());
			
			boolean bool = userAccountMapper.updateByPrimaryKeySelective(updateAccount) > 0;
			if (bool) {
				// 插入操作记录
				
				this.createPaymentDetail(account.getUserId(), null, account.getAccountId(), account.getAccountId(), orderId,  
						DDIC.TradeDetailType.TRADE_DETAIL_TYPE_PAYOUT.id, paymentType.getRemark(), freezeAmount, OperatePaymentRemark.WITHDRAW.getRemark());
				
				return bool;
			}
			
			throw new CoinWalletOperationException(RetResultCode.HANDLER_FIELED, "Operation failed, maybe the version number is wrong.");
		}
		
	}

	@Override
	public boolean unfreezeAmount(Long accountId, BigDecimal freezeAmount, OperatePaymentType paymentType, Long orderId) throws Exception {

		// 获取账户
		UserAccount account = userAccountMapper.fetchAccountById(accountId);
		this.vaildateUserAccount(account, true);
		
		// 冻结资金 < 解冻资金
		// 冻结资金 >= 解冻资金
		if (account.getFreeze().max(freezeAmount) == freezeAmount) {
			throw new CoinWalletFreezeNotEnoughException(RetResultCode.E30005);
		} else {
			// 解锁账号资金
			UserAccount updateAccount = new UserAccount();
			updateAccount.setAccountId(account.getAccountId());
			updateAccount.setFreeze(account.getFreeze().subtract(freezeAmount));
			updateAccount.setBalance(account.getBalance().add(freezeAmount));
			updateAccount.setModifiedTime(new Date());
			
			boolean bool = userAccountMapper.updateByPrimaryKeySelective(updateAccount) > 0;
			
			if (bool) {
				// 插入操作记录
				this.createPaymentDetail(account.getUserId(), null, account.getAccountId(), account.getAccountId(), orderId,  
						DDIC.TradeDetailType.TRADE_DETAIL_TYPE_PAYOUT.id, paymentType.getRemark(), freezeAmount, OperatePaymentRemark.WITHDRAW.getRemark());
				
				return bool;
			}
			
			throw new CoinWalletOperationException(RetResultCode.HANDLER_FIELED, "Operation failed, maybe the version number is wrong.");
		}
		
	}

	@Override
	public boolean transferAmount(long reduceAccountId, long addAccountId, BigDecimal increment, OperatePaymentType paymentType, long orderId) throws Exception {

		// 获取账户
		UserAccount outAccount = userAccountMapper.fetchAccountById(reduceAccountId);
		this.vaildateUserAccount(outAccount, true);
		
		if (outAccount.getBalance().max(increment) == increment) {
			throw new CoinWalletBalanceNotEnoughException(RetResultCode.E30007);
		}

		// 扣减账号
		UserAccount updateAccount = new UserAccount();
		updateAccount.setAccountId(reduceAccountId);
		updateAccount.setBalance(outAccount.getBalance().subtract(increment));
		updateAccount.setModifiedTime(new Date());
		
		boolean bool = userAccountMapper.updateByPrimaryKeySelective(updateAccount) > 0;
		if (bool) {
			// 收入账户
			UserAccount inAccount = userAccountMapper.fetchAccountById(addAccountId);
			this.vaildateUserAccount(inAccount, true);
			
			// 增加账户余额
			updateAccount = new UserAccount();
			updateAccount.setAccountId(addAccountId);
			updateAccount.setBalance(inAccount.getBalance().add(increment));
			updateAccount.setModifiedTime(new Date());
			
			bool = userAccountMapper.updateByPrimaryKeySelective(updateAccount) > 0;
			
			if (bool) {
				// 增加交易详情
				this.createPaymentDetail(outAccount.getUserId(), null, reduceAccountId, addAccountId, orderId, DDIC.TradeDetailType.TRADE_DETAIL_TYPE_PAYOUT.id, 
						paymentType.getRemark(), increment, OperatePaymentRemark.OUT.getRemark());
				this.createPaymentDetail(inAccount.getUserId(), null, addAccountId, reduceAccountId, orderId, DDIC.TradeDetailType.TRADE_DETAIL_TYPE_INCOME.id, 
						paymentType.getRemark(), increment, OperatePaymentRemark.IN.getRemark());
				
				return true;
			}
		}
		
		throw new CoinWalletOperationException(RetResultCode.HANDLER_FIELED, "Operation failed, maybe the version number is wrong.");
	}

	@Override
	public boolean withdrawalsAmount(long accountId, BigDecimal increment, OperatePaymentType paymentType) throws Exception {

		// 获取账户
		UserAccount account = userAccountMapper.fetchAccountById(accountId);
		this.vaildateUserAccount(account, true);
		
		VaildateHelper.vaildateBooleanResult(account.getBalance().max(increment) == increment, RetResultCode.E11001, "账号余额不足");
		
		// 扣减账号
		UserAccount updateAccount = new UserAccount();
		updateAccount.setAccountId(accountId);
		updateAccount.setBalance(account.getBalance().subtract(increment));
		updateAccount.setModifiedTime(new Date());
		
		boolean bool = userAccountMapper.updateByPrimaryKeySelective(updateAccount) > 0;
		
		if (bool) {
			this.createPaymentDetail(account.getUserId(), null, accountId, accountId, 0L, DDIC.TradeDetailType.TRADE_DETAIL_TYPE_PAYOUT.id, 
					paymentType.getRemark(), increment, OperatePaymentRemark.WITHDRAW.getRemark());

			return true;
		}
		
		throw new CoinWalletOperationException(RetResultCode.HANDLER_FIELED, "Operation failed, maybe the version number is wrong.");
	}

	@Override
	public UserAccount fetchAccountByUserId(Long userId) throws Exception {

		return userAccountMapper.fetchAccountByUserId(userId);
	}

}
